# -*- coding: utf-8 -*-
import librosa
import requests
import os, shutil
import glob
import cv2
import numpy as np
from PIL import Image
from moviepy.editor import *
import subprocess
import time
import random

root_path     = 'materials'
basecover_img = 'materials_base/cover.jpg'  # 封面图片
basemp4_path  = 'materials_base/base.mp4'   # 过场视频背景
basemp4_start = 'materials_base/start.mp4'  # 片头视频
basemp4_end   = 'materials_base/end.mp4'    # 片尾视频
font_path     = 'font/kaiti.ttf'

content = '加VX kkk  '

from aip import AipSpeech
"""读取文字转语音 加载百度AIP账号"""
APP_ID = '24169882'
API_KEY = 'bIqZFhHAmVCocZaZAYGmvp4r'
SECRET_KEY = 'sFefMeoX0R54xI1S1ksMej2lHnalYgKy'
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)

def StrToMp3(title, content):
    # 生成mp3解说音频
    mp3_path = os.path.join(root_path, title, 'cache', 'audio.mp3')
    result = client.synthesis(content, 'zh', 1, {'vol': 15, 'spd': 5, 'per': 0})
    if not isinstance(result, dict):
        with open(mp3_path, 'wb') as f:
            f.write(result)
    print('[%s] mp3音频已生成' % mp3_path)

def clean_word(word, inline_word=12):
    # 对文字字幕进行分行处理
    word_len = int(len(word) / inline_word)
    word_num = 0
    while word_num <= word_len:
        if word_num == 0:
            strs = word[:(word_num + 1) * inline_word] + "\n"
        else:
            strs = strs + word[word_num * inline_word:(word_num + 1) * inline_word] + "\n"
        word_num = word_num + 1
    return word_len, strs

def CutImage(file, new_path):
    # 图片重切
    img = Image.open(file)
    img_size = img.size
    h = img_size[1]  # 图片高度
    w = img_size[0]  # 图片宽度
    '''
    x = int((w - 720) / 2)
    y = int((h - 1280) / 2)
    w = 720
    h = 1280
    '''
    x = 0.05 * w
    y = 0.05 * h
    w = 0.9 * w
    h = 0.9 * h

    region = img.crop((x, y, x + w, y + h))
    region.save(new_path)

def CleanImage(title, clean_old=False):
    # 清洗原始图片到clean_jpg
    cache_path  = os.path.join(root_path, title, 'cache')
    if not os.path.exists(os.path.join(cache_path)):
        os.makedirs(cache_path)

    for file in glob.glob(os.path.join(root_path, title, '*.jpg')):
        try:
            new_path = os.path.join(cache_path, os.path.basename(file))
            # 读取图片
            img = cv2.imdecode(np.fromfile(file, dtype=np.uint8), cv2.IMREAD_COLOR)
            # 获取图片像素大小
            h , w = img.shape[0:2]
            if w >= h :
                # 横板图片缩放或者重切
                # CutImage(file, new_path)
                w = int((1280 / h) * w)
                h = 1280
            else:
                # 竖板图片缩放
                h = int((720 / w) * h)
                w = 720
            crop_size = (w, h)
            img_new = cv2.resize(img, crop_size, interpolation = cv2.INTER_CUBIC)
            cv2.imencode('.jpg', img_new)[1].tofile(new_path)

            CutImage(new_path, new_path)

            # 是否删除原始图片
            if clean_old:
                os.remove(file)
        except Exception as e:
            print('[%s] > 图片素材异常，已跳过' % file)

    print('[%s] > 图片修剪完成' % cache_path)


def MakeCoverVideo(title):
    # 封面图片生成视频
    fourcc = cv2.VideoWriter_fourcc('M', 'J', 'P', 'G')
    cover_path = os.path.join(root_path, title, 'cache', 'cover.mp4')
    vw = cv2.VideoWriter(cover_path, fourcc=fourcc, fps=10, frameSize=(720, 1280))
    jpg_list   = glob.glob(os.path.join(root_path, title, 'cache', '*.jpg'))
    cover_image = jpg_list[0] if len(jpg_list) > 0 else basecover_img
    f_read = cv2.imdecode(np.fromfile(cover_image, dtype=np.uint8), cv2.IMREAD_COLOR)
    f_img = Image.fromarray(f_read)
    f_rs = f_img.resize([720, 1280], resample=Image.NONE)
    f_out = np.array(f_rs)
    vw.write(f_out)
    vw.release()
    print('[%s] > 封面视频生成' % cover_path)

def AddImageInBase(mp3_duration, title):
    # 将图片按照顺序逐一放入movei模板中
    start_time = 0
    image_list = []
    jpg_list   = glob.glob(os.path.join(root_path, title, 'cache', '*.jpg'))
    if len(jpg_list) > 10:
        jpg_list = jpg_list[:10]
    for file in jpg_list:
        # 每段字幕时长
        every_part_duration_time = mp3_duration / len(jpg_list)

        image_clip = (
            ImageClip(file)
                .set_duration(every_part_duration_time)  # 持续时间
                .resize(width=720)  # 图片高度，会等比缩放
                .crossfadein(0)
                .set_pos(("center", "center"))  # 位置
                .set_start(start_time)
        )
        start_time = start_time + every_part_duration_time
        image_list.append(image_clip)

    # 载入背景视频
    video = VideoFileClip(basemp4_path).resize((720, 1280)).subclip(0, mp3_duration)
    cvc = CompositeVideoClip([video] + image_list, size=(720, 1280))
    jpg_path = os.path.join(root_path, title, 'cache', 'jpg.mp4')
    cvc.write_videofile(jpg_path, fps=60, remove_temp=True, verbose=True)
    print('[%s] > 图片和背景视频合成' % jpg_path)


def AddStrsAndMp3InBase(strs_list, mp3_duration, title):
    # 将字幕按照顺序逐一放入movei模板中
    # 合成字幕到模板视频中
    start_time = 0
    result_list = []
    for num in range(len(strs_list)):
        # 获取该字段字符串
        words = strs_list[num]
        # 每段字幕时长
        every_part_duration_time = mp3_duration / len(strs_list)
        # 字幕数据
        title_clip = (
            TextClip(strs_list[num], font=font_path, fontsize=50, color='red', method='label')
                .set_position(("center", 720))
                .set_duration(every_part_duration_time)
                .set_start(start_time)
        )
        start_time = start_time + every_part_duration_time
        result_list.append(title_clip)

    jpg_path = os.path.join(root_path, title, 'cache', 'jpg.mp4')
    ret_path = os.path.join(root_path, title, 'cache', 'video.mp4')

    def random_select_audio(path='audio', typ='*.mp3'):
        audio_list=[]
        for file in glob.glob(os.path.join(path, typ)):
            audio_list.append(file)
        return random.choice(audio_list)
    mp3_path  = random_select_audio()
    _duration = librosa.get_duration(filename=mp3_path)
    _st = random.randint(1, int(_duration) - mp3_duration)
    audio = AudioFileClip(mp3_path).subclip(_st, _st+mp3_duration)
    #todo: 给video合并一个随机背景音频进去
    video = VideoFileClip(jpg_path).resize((720, 1280)).set_duration(mp3_duration).set_audio(audio)
    cvc = CompositeVideoClip([video] + result_list, size=(720, 1280))
    cvc.write_videofile(ret_path, fps=60, remove_temp=True, verbose=True)

    print('[%s] > 字幕、配音和背景视频合成' % ret_path)


def StitchingAllVideo(title):
    L = []
    size = (720, 1280)
    # 片头
    cover_path = os.path.join(root_path, title, 'cache', 'cover.mp4')
    video = VideoFileClip(cover_path).resize(size)
    video = video.set_duration(1)
    video = video.without_audio()
    L.append(video)

    # 正片
    ret_path = os.path.join(root_path, title, 'cache', 'video.mp4')
    video = VideoFileClip(ret_path).resize(size).fadein(2, (1, 1, 1))
    L.append(video)
    # 片尾
    '''
    video = VideoFileClip(path_end).resize(size)
    video = video.set_duration(1)
    video = video.without_audio()
    L.append(video)
    '''
    final_clip = concatenate_videoclips(L)
    # 生成目标视频文件
    if not os.path.exists('dist'):
        os.mkdir('dist')
    _path = os.path.join('dist', '%s.mp4' % title)
    final_clip.to_videofile(_path, fps=60, remove_temp=True)
    print('[%s] > 视频组装完成' % _path)

def clearCacheFiles(title):
    # 清理缓存文件
    _path = os.path.join(root_path, title, 'cache')
    #shutil.rmtree(_path)
    for f in glob.glob(os.path.join('./', '*.mp3')):
        os.remove(f)

def main():

    for title in os.listdir(root_path):
        stime = time.time()
        CleanImage(title, clean_old=False)
        # 生成封面视频
        MakeCoverVideo(title)
        # 获取字幕行数和字幕
        word_len , strs = clean_word(content)
        # 去除无用的空list避免报错
        strs_list = strs.split("\n")
        strs_list = [i for i in strs_list if i != ""] 
        # 生成MP3文件
        # StrToMp3(title, content)
        mp3_duration = random.randint(15,45)

        # 图片合并到过场视频
        AddImageInBase(mp3_duration, title)
        # 将字幕按照顺序逐一放入movei模板中
        AddStrsAndMp3InBase(strs_list, mp3_duration, title)
        # 拼接全部视频 片头， 片尾， 封面
        StitchingAllVideo(title)

        #todo: 重新配音

        clearCacheFiles(title)

        etime = time.time()
        print('time used： %ss' % str(etime - stime))

if __name__ == '__main__':
    main()